﻿/**
 * Copyright (C) 2012-2013 original author and authors
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using NGuice.Inject.Spi;
using NGuice.Inject.Internal.Util;

namespace NGuice.Inject.Internal
{
    //complete!
    internal sealed class LinkedProviderBindingImpl<T> : BindingImpl<T>, IProviderKeyBinding<T>, IHasDependencies
    {
        readonly Key providerKey;

        public LinkedProviderBindingImpl(InjectorImpl injector, Key<T> key, object source,
                                         InternalFactory<T> internalFactory, Scoping scoping,
                                         Key providerKey)
            : base(injector, key, source, internalFactory, scoping)
        {
            Preconditions.CheckSubGenericParameter<IProvider<T>>(providerKey);
            this.providerKey = providerKey;
        }

        internal LinkedProviderBindingImpl(object source, Key<T> key, Scoping scoping, Key providerKey)
            : base(source, key, scoping)
        {
            Preconditions.CheckSubGenericParameter<IProvider<T>>(providerKey);
            this.providerKey = providerKey;
        }

        public override V AcceptTargetVisitor<V>(IBindingTargetVisitor<T, V> visitor)
        {
            return visitor.Visit((IProviderKeyBinding<T>)this);
        }

        public Key ProviderKey
        {
            get { return providerKey; }
        }

        public ISet<Dependency> Dependencies
        {
            get { return ImmutableSet<Dependency>.Of(Dependency<IProvider<T>>.GetForNoGeneric(providerKey)); }
        }

        public BindingImpl<T> WithScoping(Scoping scoping)
        {
            return new LinkedProviderBindingImpl<T>(Source, Key, scoping, providerKey);
        }

        public BindingImpl<T> WithKey(Key<T> key)
        {
            return new LinkedProviderBindingImpl<T>(Source, key, Scoping, providerKey);
        }

        public override void ApplyTo(IBinder binder)
        {
            Scoping.ApplyTo(binder.WithSource(Source).Bind(Key).ToProviderNoGenericKey(providerKey));
        }

        public override string ToString()
        {
            return new ToStringBuilder(typeof(IProviderKeyBinding<>))
                .Add("key", Key)
                .Add("source", Source)
                .Add("scope", Scoping)
                .Add("provider", providerKey)
                .ToString();
        }

        public override bool Equals(object obj)
        {
            if (obj is LinkedProviderBindingImpl<T>)
            {
                LinkedProviderBindingImpl<T> o = (LinkedProviderBindingImpl<T>)obj;
                return Key.Equals(o.Key)
                  && Scoping.Equals(o.Scoping)
                  && Objects.Equal(providerKey, o.providerKey);
            }
            else
            {
                return false;
            }
        }

        public int GetHashCode()
        {
            return Objects.GetHashCode(Key, Scoping, providerKey);
        }

    }
}
